#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""当我们想对一个对象添加额外的功能时，通常有以下不同的可选方法：

如果合理，可以直接将功能添加到对象所属的类
使用组合
使用继承
与继承相比，通常应该优先选择组合，因为继承使得代码更难复用，继承关系是静态的，并且应用于整个类以及这个类的所有实例。
设计模式提供了第四种方法：支持动态地(运行时)扩展一个对象的功能。
使用修饰器模式使斐波那契数列和计算前n个数的和更加快速。"""

from functools import wraps

def memoize(fn):
    known = dict()
    @wraps(fn)
    def memeoizer(*args):
        if args not in known:
            known[args] = fn(*args)
        return known[args]
    return memeoizer

@memoize
def nsum(n):
    """返回前n个数字的和"""
    assert (n>=0)
    return 0 if n==0 else n+nsum(n-1)

@memoize
def fibonacci(n):
    """返回斐波那契数列的第n个数"""
    assert (n>=0)
    return n if n==0 or n==1 else fibonacci(n-1)+fibonacci(n-2)

if __name__ == "__main__":
    from timeit import Timer
    measure = [
        {'exec':'fibonacci(3)', 'import':'fibonacci', 'func':fibonacci},
        {'exec':'nsum(2)', 'import':'nsum', 'func':nsum}
    ]
    for m in measure:
        t = Timer("{}".format(m["exec"]),"from __main__ import {}".format(m["import"]))
        print("name:{},doc:{},executing:{},time:{}".format(m["func"].__name__,m["func"].__doc__,m["exec"],t.timeit()))
